package com.xinyue.auto.reader.process;

import java.util.List;

import org.dom4j.Element;

import com.xinyue.auto.bean.Query;
import com.xinyue.auto.exception.DynamicException;
import com.xinyue.auto.reader.Process;
import com.xinyue.auto.reader.major.FindMajor;
import com.xinyue.auto.reader.util.ReturnTypeUtil;
import com.xinyue.auto.type.Type;
import com.xinyue.auto.util.StringUtil;

public class DynamicProcess extends FindMajor implements Type{
	public DynamicProcess(Process read) {
		super(read);
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void validate() throws Exception {
		Element find = xml.element(finder_);
		if(find != null) {
			//读取dynamic标签
			List<Element> ds = find.elements(dynamic_);
			
			if(ds != null && ds.size() > 0) {
				try {
					for (Element dynamic: ds) {
						//读取公共属性
						Query q = commonRead(dynamic);
						q.setType(dyncType);
						
						//返回值、强制类型转换、是否单个结果集处理
						dynamicReturn(dynamic, q);
						//入参，分页处理
						dynamicParam(dynamic, q);
						//hql语句
						String countState = processQL(dynamic, q);
						//Count查询
						countProcess(q, countState);
						
						querys.add(q);
					}
				} catch (Exception e) {
					throw new DynamicException(e.getMessage(), holder.getException());
				}
			}
		}
	}
	
	/**
	 * dynamic返回值
	 * @param dynamic
	 * @param q
	 * @throws Exception
	 */
	private void dynamicReturn(Element dynamic, Query q) throws Exception {
		String entity = xml.attributeValue(name_);
		
		String type = dynamic.attributeValue(returnType_);
		String dto = dynamic.attributeValue(dto_);
		if(StringUtil.isNull(type)) {
			throw new Exception("未定义returnType属性或其值为空");
		}
		
		//如果未定义dto属性，则按一般情况处理，反之其返回值只能是DTO或者LIST
		if(StringUtil.isNull(dto)) {
			if(entity.equals(type)) {
				q.setConvert(true);
				q.setOnly(true);
				q.setReturnType(entity);
			}else if(LIST.equals(type)) {
				q.setWarning(true);
				q.setReturnType("List<" + entity + ">");
			}else if(COUNT.equals(type)) {
				q.setConvert(true);
				q.setOnly(true);
				q.setReturnType(LONG_);
			}else {
				String impt = ReturnTypeUtil.validate(type, q);
				if(impt != null) {
					holder.getDaoImpt().add(impt);
				}
			}
		}else {
			if(dto.indexOf(".") < 1) {
				throw new Exception("dto属性值非法，不是标准的Java对象：" + dto);
			}
			
			String bean = StringUtil.getNameByDoc(dto);
			if(DTO.equals(type)) {
				q.setConvert(true);
				q.setOnly(true);
				q.setReturnType(bean);
			}else if(LIST.equals(type)) {
				q.setWarning(true);
				q.setReturnType("List<" + bean + ">");
			}else {
				throw new Exception("定义了dto属性，则返回值只能是DTO或者List");
			}
			
			q.setDto(bean);
			holder.getDaoImpt().add(dto);
			holder.getDaoImptExt().add("org.hibernate.transform.Transformers");
		}
	}
	
	/**
	 * 入参处理
	 * @param dynamic
	 * @param q
	 * @throws Exception
	 */
	private void dynamicParam(Element dynamic, Query q) throws Exception {
		//是否对查询添加分页处理
		String paging = dynamic.attributeValue(paging_);
		//是否是sql查询：当为sql查询时，不会对查询进行hibernate形式的分页处理
		String sql = dynamic.attributeValue(sql_);
		
		if("true".equals(sql)) {
			q.setSql(true);
			holder.getDaoImptExt().add("org.hibernate.SQLQuery");
		}
		
		if("true".equals(paging)) {
			q.setParams("Map<String, Object> map, int begin, int count");
			q.setParamsIn("map, begin, count");
			q.setPaging(true);
		}else {
			q.setParams("Map<String, Object> map");
			q.setParamsIn("map");
		}
		
		holder.getDaoImpt().add("java.util.Map");
		holder.getDaoImptExt().add("commons.DaoUtil");
	}
	
	/**
	 * 对SQL语句进行预处理
	 * @throws FinderException 
	 */
	@SuppressWarnings("unchecked")
	protected String processQL(Element dynamic, Query q) throws Exception {
		String count_s = null;
		String select_s = null;
		String ql = null;
		
		//count子句和select子句处理
		Element count = dynamic.element(count_);
		Element select = dynamic.element(select_);
		if(count != null) {
			count_s = count.getTextTrim();
			if(StringUtil.isNull(count_s)) {
				throw new Exception("count标签中的语句未定义");
			}
		}
		
		if(select == null) {
			throw new Exception("select标签未定义");
		}else {
			select_s = select.getTextTrim();
			if(StringUtil.isNull(select_s)) {
				throw new Exception("select标签中的语句未定义");
			}
		}
		
		Element state = dynamic.element(state_);
		if(state == null) {
			throw new Exception("未定义查询语句state标签或其值为空");
		}
		
		List<Element> nulls = state.elements(isNotNull_);
		
		/**SQL处理方法
		 * 解析xml，将isNotNull标签下的数据转化成SQL，并替换isNotNull标签内的字符为@+数字
		 */
		if(nulls != null && nulls.size() > 0) {
			//sql字符集处理
			String paramArray = "";
			for (int i = 0; i < nulls.size(); i++) {
				paramArray += "\"" + nulls.get(i).getTextTrim() + "\", \"" + nulls.get(i).attributeValue(key_) + "\", ";
				//替换字符集为@+数字
				nulls.get(i).setText("@" + i);
			}
			q.setParamArray(paramArray.substring(0, paramArray.length() - 2));
			
			String reg = state.getStringValue();
			//去除字符集中的制表符、回车，并将前后空格去除，最后将多空格合一。
			ql = reg.replaceAll("\t|\r|\n", " ").replaceAll("[\\s]+", " ").replaceAll("^[ ]*", "").replaceAll("[ ]*$", "");
			
			q.setState(select_s + " " + ql);
			holder.getDaoImptExt().add("commons.DaoUtil");
		}else {
			ql = state.getTextTrim();
			q.setState(select_s + " " + state.getTextTrim());
		}
		
		q.setState(select_s + " " + ql);
		
		if(count_s == null) {
			return null;
		}else {
			return count_s + " " + ql;
		}
	}
	
	/**
	 * 处理查询总数量的语句
	 * @param q
	 * @param state
	 * @return
	 */
	private void countProcess(Query q, String state) {
		if(!StringUtil.isNull(state)) {
			Query count = new Query();
			count.setType(dyncType);
			
			count.setConvert(true);
			count.setParams("Map<String, Object> map");
			count.setParamsIn("map");
			count.setOnly(true);
			count.setReturnType(LONG_);
			count.setMethod(q.getMethod() + "Count");
			count.setParamArray(q.getParamArray());
			count.setSql(q.isSql());
			count.setState(state);
			
			querys.add(count);
		}
	}
}